#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/delay.h>

/**
 * When you have only one slave, then you can directly connect the SS/CS pin to the ground if your slave permits it.
 *
 * https://embetronicx.com/tutorials/tech_devices/spi-serial-peripheral-interface-protocol-basics/
 *
 * https://www.cnblogs.com/tansuoxinweilai/p/11405029.html
 *
 *
 *
 *
 *
 *
 *
 */

static struct spi_device *my_spi_device;

int my_spi_write(void) {
	const u8 data = 0xe3;
	int ret = -1;
	u8 rx = 0x00;
	struct spi_transfer tr = { .tx_buf = &data, .rx_buf = &rx, .len = 1, };
	dev_info(&my_spi_device->dev, "rx = %d.\n", rx);
	ret = spi_sync_transfer(my_spi_device, &tr, 1);
	if (ret) {
		pr_err("spi_sync_transfer failed\n");
		return ret;
	}
	dev_info(&my_spi_device->dev, "spi_sync_transfer ret = %d\n", ret);
	dev_info(&my_spi_device->dev, "rx = %d.\n", rx);
	if (rx == data)
		dev_info(&my_spi_device->dev, "spi_sync_transfer success \n");
	else
		dev_info(&my_spi_device->dev, "spi_sync_transfer failed \n");
	return 0;
}


int my_spi_write2(void) {
	const int length = 4;
	const u8 data[] = { 4, 5, 6, 7 };
	int ret = -1;
	u8 *rx = kmalloc(length, GFP_KERNEL);
	struct spi_transfer tr = { .tx_buf = data, .rx_buf = rx, .len = length, };

	ret = spi_sync_transfer(my_spi_device, &tr, 1);
	if (ret) {
		pr_err("spi_sync_transfer failed\n");
		return ret;
	}
	dev_info(&my_spi_device->dev, "spi_sync_transfer ret = %d\n", ret);
	dev_info(&my_spi_device->dev, "spi_sync_transfer success \n");
	dev_info(&my_spi_device->dev, "spi_sync_transfer read rx0 = %d\n", *rx);
	dev_info(&my_spi_device->dev, "spi_sync_transfer read rx1 = %d\n", *(rx + 1));
	dev_info(&my_spi_device->dev, "spi_sync_transfer readr x2 = %d\n", *(rx + 2));
	dev_info(&my_spi_device->dev, "spi_sync_transfer read rx3 = %d\n", *(rx + 3));
	return 0;
}

static const struct of_device_id spidev_dt_ids[] = {
		{ .compatible = "myspidev" }, { }, };

MODULE_DEVICE_TABLE(of, spidev_dt_ids);

int my_probe(struct spi_device *spi) {
	my_spi_device = spi;
	dev_info(&spi->dev, "my_probe start.\n");
	dev_info(&spi->dev, "master->bus_num = %d\n", spi->master->bus_num);
	dev_info(&spi->dev, "chip_select = %d\n", spi->chip_select);
	dev_info(&spi->dev, "bits_per_word = %d\n", spi->bits_per_word);
	return my_spi_write();;
}

int my_remove(struct spi_device *spi) {
	dev_info(&spi->dev, "my_remove start.\n");
	return 0;
}

static struct spi_driver spidev_spi_driver = { .driver = { .name = "myspidev",
		.of_match_table = of_match_ptr(spidev_dt_ids), }, .probe = my_probe,
		.remove = my_remove, };

module_spi_driver(spidev_spi_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andy");
MODULE_DESCRIPTION("A sample c  driver");
